package
{
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	
	import flash.display.Shader;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.AccelerometerEvent;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.StageOrientationEvent;
	import flash.geom.Point;
	import flash.sensors.Accelerometer;
	import flash.system.Capabilities;
	import flash.utils.getTimer;
	
	import utils.FPSShow;
	
	public final class Box2dTest extends Sprite
	{
		private const PIXELS_TO_METRE:int = 30;
		private const SWF_HALF_WIDTH:int = 400;
		private const SWF_HEIGHT:int = 600;
		private var _world:b2World;
		private var stageWidth:Number;
		private var stageHeight:Number;
		private var box:b2Body;
		public function Box2dTest()
		{
			super();
			
			// 支持 autoOrient
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.frameRate = 60;
			if(Capabilities.screenResolutionX>Capabilities.screenResolutionY){
				stageWidth=Capabilities.screenResolutionY;
				stageHeight=Capabilities.screenResolutionX;
			}else{
				stageHeight=Capabilities.screenResolutionY;
				stageWidth=Capabilities.screenResolutionX;
			}
			
			stageHeight=480;
			stageWidth=320;
			this.steupPhysicsWorld();
			
			box=addBox(new Point(stageWidth/2, stageHeight), stageWidth/10, 20, false, 1, 1);
//			this.addBox(new Point(SWF_HALF_WIDTH, 4), 30, 30, true, 1, 0.3);
			stage.addChild(new FPSShow());
			
			if(Accelerometer.isSupported){
				var locale:Accelerometer = new Accelerometer();
				locale.setRequestedUpdateInterval(1000/stage.frameRate);
				locale.addEventListener(AccelerometerEvent.UPDATE, onlocationHandler);
			}else{
				stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMoveHandler);
			}
			stage.addEventListener(Event.ENTER_FRAME, worldUpdate);
			stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGE,orientain_change);
			
		}
		
		private function orientain_change(orientation:StageOrientationEvent):void{
			if(Capabilities.screenResolutionX>Capabilities.screenResolutionY){
				stageWidth=Capabilities.screenResolutionY;
				stageHeight=Capabilities.screenResolutionX;
			}else{
				stageHeight=Capabilities.screenResolutionY;
				stageWidth=Capabilities.screenResolutionX;
			}
			var b2v:b2Vec2 = box.GetPosition();
			b2v.y = stageHeight/PIXELS_TO_METRE;
//			box.GetFixtureList().GetShape()
			box.SetPosition(b2v);
		}
		
		
		private var accelerg:Number =0;
		private var ispaint:Boolean=false;
		private function onlocationHandler(e:AccelerometerEvent):void{
			var b2v:b2Vec2 = box.GetPosition();
			var t:Number  = b2v.x*PIXELS_TO_METRE-(e.accelerationX*50);
			if(t>0 &&t<stageWidth){
				b2v.x = t/PIXELS_TO_METRE;
				box.SetPosition(b2v);
				ispaint=true;
			}
		}
		
		
		private function onMouseMoveHandler(e:MouseEvent):void{
			
			var t:Number = this.mouseX;
			if(t>0 &&t<stageWidth){
				var b2v:b2Vec2 = box.GetPosition();
				b2v.x = t/PIXELS_TO_METRE;
				box.SetPosition(b2v);
				ispaint=true;
			}
			
		}
		
		
		private function addCircle(position:Point, halfWidth:Number, density:Number = 0, friction:Number = 0, restitution:Number = 0):void{
			
			var body:b2Body = _world.GetBodyList();
			
			while(body){
				var net:b2Body = body.GetNext();
				if(body.GetPosition().y>box.GetPosition().y){
//					var b2v:b2Vec2 = body.GetPosition();
//					b2v.x = position.x/PIXELS_TO_METRE;
//					b2v.y = position.y / PIXELS_TO_METRE;
					_world.DestroyBody(body);
//					body.SetPosition(b2v);
//					return;
//					trace("删除");
				}
				body=net;
			}
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type = b2Body.b2_dynamicBody;
			bodyDef.linearDamping = 0;
			bodyDef.angularDamping = 20;
			bodyDef.position.Set(position.x /PIXELS_TO_METRE,position.y / PIXELS_TO_METRE);
			
			body = this._world.CreateBody(bodyDef);
			
			var boxShape:b2CircleShape = new b2CircleShape();
			boxShape.SetRadius(halfWidth / PIXELS_TO_METRE);
			
			var boxFixtureDef:b2FixtureDef = new b2FixtureDef();
			boxFixtureDef.shape = boxShape;
			boxFixtureDef.density = density;
			boxFixtureDef.friction = friction;
			boxFixtureDef.restitution = restitution;
			body.SetUserData(getCircle(position));
			body.CreateFixture(boxFixtureDef);
			
		}
		private var freeData:Vector.<Shape> = new Vector.<Shape>;
		private function getCircle(p:Point):Shape{
			var s:Shape;
			
			if(freeData.length>0){
				s= freeData.pop();
			}else{
			
				s = new Shape();
				s.graphics.beginFill(0xFF0000);
				s.graphics.drawCircle(0,0,30);
				s.graphics.endFill();
			}
			s.x = p.x;
			s.y = p.y;
			addChild(s);
			return s;
		}
		
		private function addBox(position:Point, halfWidth:Number, halfHeight:Number, isDynamic:Boolean, density:Number = 0, friction:Number = 0, restitution:Number = 0):b2Body {
			var bodyDef:b2BodyDef = new b2BodyDef();
			if (isDynamic) {
				bodyDef.type = b2Body.b2_dynamicBody;
			} else {
				bodyDef.type = b2Body.b2_staticBody;
			}
			bodyDef.position.Set(position.x /PIXELS_TO_METRE,position.y / PIXELS_TO_METRE);
			
			var body:b2Body = this._world.CreateBody(bodyDef);
			
			var boxShape:b2PolygonShape = new b2PolygonShape();
			boxShape.SetAsBox(halfWidth / PIXELS_TO_METRE, halfHeight / PIXELS_TO_METRE);
			var boxFixtureDef:b2FixtureDef = new b2FixtureDef();
			boxFixtureDef.shape = boxShape;
			boxFixtureDef.density = density;
			boxFixtureDef.friction = friction;
			boxFixtureDef.restitution = restitution;
			body.CreateFixture(boxFixtureDef);
			return body;
		}
		
		private function steupPhysicsWorld():void {
			this._world = new b2World(new b2Vec2(0, 10), true);
			_world.GetGroundBody().SetAngularDamping(10);
			addChild(this.debugDraw());
		}
		
		private function debugDraw():Sprite {
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(PIXELS_TO_METRE);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			debugDraw.SetFillAlpha(0.5);
			this._world.SetDebugDraw(debugDraw);
			return debugSprite;
		}
		
		private var t:Number=0;
		private var nt:Number =0;
		public function worldUpdate(evt: Event):void {
			var timeStep:Number = 1 / 30;
			var velocityIterations:int = 6;
			var positionIterations:int = 2;
			
			this._world.Step(timeStep, velocityIterations, positionIterations);
			this._world.ClearForces();
			this._world.DrawDebugData();
			var body:b2Body = _world.GetBodyList();
			
			while(body){
				var net:b2Body = body.GetNext();
				if(body.GetPosition().y>box.GetPosition().y){
					//					var b2v:b2Vec2 = body.GetPosition();
					//					b2v.x = position.x/PIXELS_TO_METRE;
					//					b2v.y = position.y / PIXELS_TO_METRE;
					if(body.GetUserData()){
						freeData.push(body.GetUserData());
						body.GetUserData().parent.removeChild(body.GetUserData());
					}
					_world.DestroyBody(body);
					//					body.SetPosition(b2v);
					//					return;
					//					trace("删除");
				}else{
					if(body.GetUserData()){
						body.GetUserData().x = body.GetPosition().x*PIXELS_TO_METRE;
						body.GetUserData().y=body.GetPosition().y*PIXELS_TO_METRE;
					}
				}
				body=net;
			}
			var ct:Number = getTimer();
			if((ct-t)>nt){
				t=ct;
				nt=500;
				
				addCircle(new Point( Math.random()* stageWidth, 4), 30, 1, 0.3);
			}
			
		}
		
	}
}